"""
数据模型定义（Pydantic Schema）
定义项目、剧集、镜头、资产、任务等核心数据结构
"""
from datetime import datetime
from typing import Optional, List, Dict, Any, Literal
from pydantic import BaseModel, Field
import json


class Project(BaseModel):
    """项目模型"""
    id: str = Field(..., description="项目ID")
    name: str = Field(..., description="项目名称")
    genre: Optional[str] = Field(None, description="题材类型")
    status: Optional[str] = Field("draft", description="项目状态")
    createdAt: datetime = Field(default_factory=datetime.now, description="创建时间")

    class Config:
        json_schema_extra = {
            "example": {
                "id": "proj_001",
                "name": "DemoProject",
                "genre": "都市爽文",
                "status": "draft",
                "createdAt": "2024-01-01T00:00:00"
            }
        }


class ReferenceImage(BaseModel):
    """参考图模型"""
    id: str = Field(..., description="参考图ID")
    path: str = Field(..., description="文件路径")
    type: str = Field(..., description="类型：front_view/side_view/expression_smile等")
    selected: bool = Field(False, description="是否被选为主参考图")
    seed: Optional[int] = Field(None, description="生成种子")
    prompt: Optional[str] = Field(None, description="生成提示词")
    generatedAt: datetime = Field(default_factory=datetime.now, description="生成时间")
    provider: Optional[str] = Field(None, description="生成提供商")
    resolution: Optional[str] = Field(None, description="分辨率")
    age: Optional[int] = Field(
        None,
        description="该参考图对应的年龄阶段（可选，例如 18 表示 18 岁左右形象）"
    )
    episodeRange: Optional[str] = Field(
        None,
        description="该参考图适用的剧集范围，例如 '1-20'（可选）"
    )
    timeLabel: Optional[str] = Field(
        None,
        description="时间/阶段标签，例如 '高中时期'、'末日前'、'末日25年后'（可选）"
    )


class Character(BaseModel):
    """人物模型"""
    id: str = Field(..., description="人物ID")
    projectId: str = Field(..., description="所属项目ID")
    name: str = Field(..., description="人物姓名")
    role: Optional[str] = Field(None, description="角色定位：主角/主要配角/次要角色")
    bio: Optional[str] = Field(None, description="人物简介")
    visualDescription: Optional[str] = Field(None, description="视觉描述：外貌、气质、服装等")
    traits: Optional[List[str]] = Field(default_factory=list, description="人物特征")
    goals: Optional[List[str]] = Field(default_factory=list, description="人物目标")
    conflicts: Optional[List[str]] = Field(default_factory=list, description="冲突点")
    voiceId: Optional[str] = Field(None, description="音色ID")
    voiceProfile: Optional[Dict[str, Any]] = Field(None, description="音色配置")
    referenceImages: List[ReferenceImage] = Field(default_factory=list, description="参考图列表")
    primaryReference: Optional[str] = Field(None, description="主参考图路径（视觉锚点）")
    locked: bool = Field(False, description="是否已锁定（完成人物定型）")
    lockedAt: Optional[datetime] = Field(None, description="锁定时间")
    stylePrompt: Optional[str] = Field(None, description="风格提示词")
    negativePrompt: Optional[str] = Field(None, description="负面提示词")
    # 兼容旧字段
    refs: Optional[List[str]] = Field(default_factory=list, description="参考图路径列表（已弃用）")
    identityRef: Optional[str] = Field(None, description="身份向量/参考图路径（已弃用）")


class Episode(BaseModel):
    """剧集模型"""
    id: str = Field(..., description="剧集ID")
    projectId: str = Field(..., description="所属项目ID")
    index: int = Field(..., description="剧集序号")
    outline: Optional[str] = Field(None, description="剧集大纲")
    scriptJSON: Dict[str, Any] = Field(default_factory=dict, description="剧本JSON")
    status: str = Field("draft", description="状态")
    versions: List[str] = Field(default_factory=list, description="版本列表")


class ShotPlan(BaseModel):
    """镜头计划模型"""
    shotIndex: int = Field(..., description="镜头序号")
    sceneType: str = Field(..., description="场景类型")
    framing: str = Field(..., description="景别：close-up/medium-shot/wide-shot等")
    movement: Optional[str] = Field(None, description="运动方式")
    duration: float = Field(..., description="时长（秒）")
    elements: List[str] = Field(default_factory=list, description="画面要素")
    dialogue: Optional[str] = Field(None, description="对白")
    bgmHint: Optional[str] = Field(None, description="BGM提示")


class Shot(BaseModel):
    """镜头模型"""
    id: str = Field(..., description="镜头ID")
    episodeId: str = Field(..., description="所属剧集ID")
    index: int = Field(..., description="镜头序号")
    shotPlan: ShotPlan = Field(..., description="镜头计划")
    assets: List[str] = Field(default_factory=list, description="资产ID列表")
    duration: Optional[float] = Field(None, description="实际时长")
    seed: Optional[int] = Field(None, description="随机种子")
    styleLock: Optional[str] = Field(None, description="风格锁定标识")


class Asset(BaseModel):
    """资产模型"""
    id: str = Field(..., description="资产ID")
    shotId: str = Field(..., description="所属镜头ID")
    type: Literal["image", "video", "audio", "subtitle"] = Field(..., description="资产类型")
    uri: str = Field(..., description="文件路径")
    meta: Dict[str, Any] = Field(default_factory=dict, description="元数据")
    source: Literal["manual", "external_api"] = Field(..., description="来源")
    externalProvider: Optional[str] = Field(None, description="外部提供商")
    externalJobId: Optional[str] = Field(None, description="外部任务ID")


class Job(BaseModel):
    """任务模型"""
    id: str = Field(..., description="任务ID")
    type: str = Field(..., description="任务类型")
    inputs: Dict[str, Any] = Field(default_factory=dict, description="输入参数")
    outputs: Dict[str, Any] = Field(default_factory=dict, description="输出结果")
    status: Literal["pending", "running", "succeeded", "failed"] = Field("pending", description="状态")
    error: Optional[str] = Field(None, description="错误信息")
    retry: int = Field(0, description="重试次数")
    externalProvider: Optional[str] = Field(None, description="外部提供商")
    externalJobId: Optional[str] = Field(None, description="外部任务ID")
    cost: float = Field(0.0, description="成本（美元）")
    createdAt: datetime = Field(default_factory=datetime.now, description="创建时间")
    updatedAt: datetime = Field(default_factory=datetime.now, description="更新时间")


class RoleRun(BaseModel):
    """角色运行记录模型"""
    id: str = Field(..., description="运行ID")
    role: Literal["planner", "outliner", "character_designer", "scriptwriter", "editor"] = Field(..., description="角色")
    inputs: Dict[str, Any] = Field(default_factory=dict, description="输入")
    output: Optional[Dict[str, Any]] = Field(None, description="输出")
    provider: str = Field(..., description="提供商")
    model: str = Field(..., description="模型名称")
    status: Literal["succeeded", "failed"] = Field(..., description="状态")
    cost: float = Field(0.0, description="成本")
    error: Optional[str] = Field(None, description="错误信息")
    createdAt: datetime = Field(default_factory=datetime.now, description="创建时间")


class StoryBible(BaseModel):
    """故事事实与风格库"""
    facts: List[str] = Field(default_factory=list, description="剧情事实表")
    styleGuide: Dict[str, Any] = Field(default_factory=dict, description="风格指南")


class OutlinePlan(BaseModel):
    """大纲计划模型（Planner输出）"""
    seasonThemes: List[str] = Field(default_factory=list, description="季主题列表")
    pacingCurve: Dict[str, Any] = Field(default_factory=dict, description="节奏曲线")
    episodeQuota: int = Field(..., description="剧集配额")


class EpisodeBeat(BaseModel):
    """剧集节拍模型"""
    order: Optional[int] = Field(None, description="节拍顺序")
    type: Literal["setup", "climax", "twist", "payoff"] = Field(..., description="节拍类型")
    hook: str = Field(..., description="钩子/关键情节")
    durationHint: float = Field(..., description="时长提示（秒）")
    mustHave: Optional[List[str]] = Field(default_factory=list, description="必备要素")


class EpisodeBeats(BaseModel):
    """剧集节拍集合（Outliner输出）"""
    episodeIndex: int = Field(..., description="剧集序号")
    beats: List[EpisodeBeat] = Field(default_factory=list, description="节拍列表")


class CharacterCard(BaseModel):
    """人物卡模型（Character Designer输出）"""
    name: str = Field(..., description="姓名")
    role: Optional[str] = Field(None, description="角色定位")
    bio: str = Field(..., description="简介")
    visualDescription: Optional[str] = Field(None, description="视觉描述")
    traits: List[str] = Field(default_factory=list, description="特征")
    goals: List[str] = Field(default_factory=list, description="目标")
    conflicts: List[str] = Field(default_factory=list, description="冲突")
    visualRefs: List[str] = Field(default_factory=list, description="视觉参考（已弃用）")
    referenceImages: List[str] = Field(default_factory=list, description="参考图路径列表")
    primaryReference: Optional[str] = Field(None, description="主参考图路径")
    locked: bool = Field(False, description="是否已锁定")


class ReviewReport(BaseModel):
    """评审报告模型（Editor输出）"""
    target: Literal["outliner", "scriptwriter"] = Field(..., description="评审目标")
    issues: List[str] = Field(default_factory=list, description="问题列表")
    suggestions: List[str] = Field(default_factory=list, description="建议列表")
    decision: Literal["approve", "revise"] = Field(..., description="决策")


class ScenePlan(BaseModel):
    """场景计划模型（Scriptwriter输出）"""
    id: Optional[str] = Field(None, description="场景ID")
    sceneIndex: int = Field(..., description="场景序号")
    title: Optional[str] = Field(None, description="场景标题")
    summary: str = Field(..., description="场景摘要")
    location: Optional[str] = Field(None, description="场景地点")
    characters: List[str] = Field(default_factory=list, description="出场角色")
    elements: List[str] = Field(default_factory=list, description="场景要素")
    dialogue: Optional[str] = Field(None, description="对白")
    beatsRef: Optional[List[int]] = Field(default_factory=list, description="关联的beat序号")
    durationHint: float = Field(..., description="时长提示")

